package com.aviation.sell_ticket.service.impl;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.aviation.sell_ticket.mapper.LoginMapper;
import com.aviation.sell_ticket.pojo.Aviation_login_record;
import com.aviation.sell_ticket.pojo.Aviation_user;
import com.aviation.sell_ticket.service.LoginRecordService;
import com.aviation.sell_ticket.service.LoginService;
import com.aviation.sell_ticket.tool.*;
import eu.bitwalker.useragentutils.UserAgent;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@EnableAsync
public class LoginServiceImpl implements LoginService {

    @Resource
    private LoginMapper loginMapper;//引入LoginMapper

    @Resource
    private Jwt jwt;//引入Jwt

    @Resource
    LoginRecordService loginRecordService;

    @Resource
    IpUtil ipUtil;

    @Resource
    Searcher searcher;

    @Resource
    private RedisUtil redis;//引入redis

    @Resource
    private SendMail mail;//引入SendMail

    @Resource
    private SocketIOHandler socketIOHandler;

    /**
     * 用户登录
     *
     * @param user_name     用户名
     * @param user_password 用户密码
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> login(String user_name, String user_password, HttpServletRequest request) {
        JSONObject userData = new JSONObject();
        try {
            HttpSession session =request.getSession();
            //验证用户状态
            Aviation_user aviationUser = loginMapper.Login(user_name);
            if (aviationUser == null) {
                return ResultUtil.success(ResultEnum.USER_NOT_EXIST, null);
            }

            //验证密码是否正确
            String md5Pwd = SecureUtil.md5(user_password + aviationUser.getSalt());
            if (!md5Pwd.equals(aviationUser.getUser_password())) {
                return ResultUtil.success(ResultEnum.PASSWORD_ERROR, null);
            }

            //查询是否有人在线，有就踢掉
            String sessionId = redis.getRedis("UserId:"+aviationUser.getUser_id());
            if (!Validator.isNull(sessionId)) {
                if (redis.isSetRedis("UserSession:"+sessionId)) {
                    if (!redis.deleteRedis("UserSession:"+sessionId)) {
                        return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
                    }
                    socketIOHandler.forcedReturn(sessionId);
                }
            }

            //登陆成功返回token
            String token = jwt.getToken(aviationUser.getUser_id());

            //构建json对象
            userData.put("token",token);
            userData.put("userName",user_name);
            userData.put("session",session.getId());


            //获取ipss
            String ip=IpUtil.getIpAddr(request).split(",")[0];
            //检测设备
            UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("user-agent"));
            String device=userAgent.getOperatingSystem().getDeviceType().toString();
            String deviceChinese="";
            if(device.equals("MOBILE")){
                deviceChinese="移动端";
            }else{
                deviceChinese="PC端";
            }

            if(device.isEmpty()){
                deviceChinese="未知";
            }
            //构建登录记录数据
            Aviation_login_record loginRecord=new Aviation_login_record(
                    IdUtil.simpleUUID(),
                    LocalDateTime.now(),
                    LoginServiceImpl.addressFiltering(searcher.search(ip)),
                    ip,
                    deviceChinese,
                    aviationUser.getUser_id()
            );
            //添加登录记录
            loginRecordService.addLoginRecord(loginRecord);

            //把token存入redis中
            redis.setRidesTime("UserSession:"+session.getId(), token, (long) (60 * 30), TimeUnit.SECONDS);
            //存入sessionid
            redis.setRidesTime("UserId:"+aviationUser.getUser_id(), session.getId(), (long) (60 * 30), TimeUnit.SECONDS);

        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
        return ResultUtil.success(ResultEnum.SUCCESS, userData.toString());
    }

    /**
     * 用户注册
     *
     * @param aviationUser 用户信息
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> logon(Aviation_user aviationUser, String verificationCode) {
        try {
            //验证验证码
            String isCode = redis.getRedis(aviationUser.getUser_name());
            if (Validator.isNull(isCode) || !isCode.equals(verificationCode)) {
                return ResultUtil.success(ResultEnum.INVALID_VERIFICATION_CODE, null);
            }

            //删除验证码
            redis.deleteRedis(aviationUser.getUser_name());

            //验证用户名是否已经使用
            String user_id = loginMapper.verifyUserName(aviationUser.getUser_name());
            if (user_id != null) {
                return ResultUtil.success(ResultEnum.USER_IS_EXISTS, null);
            }

            //生成密钥
            String salt = RandomUtil.randomString(6);
            //生成用户id
            aviationUser.setUser_id(IdUtil.simpleUUID());
            //生成加密密码
            aviationUser.setUser_password(SecureUtil.md5(aviationUser.getUser_password() + salt));
            //生成创建时间
            aviationUser.setRegistration_time(LocalDateTime.now());
            //设置密钥
            aviationUser.setSalt(salt);

            //向数据库新增
            int logonId = loginMapper.logon(aviationUser);
            if (logonId <= 0) {
                return ResultUtil.success(ResultEnum.LOGON_HAS_FAILED, null);
            }

        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
        return ResultUtil.success(ResultEnum.SUCCESS, null);
    }

    /**
     * 发送邮件验证码
     *
     * @param user_name 邮箱
     * @return Map<String, Object>
     */
    public Map<String, Object> emailVerificationCode(String user_name) {
        try {
            //验证验证码时间是否过期
            if (redis.isSetRedis(user_name + "exceed")) {
                return ResultUtil.success(ResultEnum.REPEATED_TRANSMISSION, null);
            }
            //生成验证码
            String verificationCode = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
            //把验证码添加到redis
            redis.setRidesTime(user_name, verificationCode, (long) 60 * 5, TimeUnit.SECONDS);
            //添加1分钟限制
            redis.setRidesTime(user_name + "exceed", "", (long) 60, TimeUnit.SECONDS);
            //发送验证码
            mail.sendVerificationCode(user_name, verificationCode);
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
        return ResultUtil.success(ResultEnum.SUCCESS, null);
    }

    /**
     * 退出登录
     *
     * @param token 用户密钥
     * @return Map<String, Object>
     */
    public Map<String, Object> loginOut(String token) {
        try {
            //验证用户密钥正确性
            DecodedJWT verify = jwt.jwtVerify(token);
            //获取用户id
            String user_id = verify.getClaim("user_idHMAC256").asString();
            //通过用户id获取sessionId
            String sessionId = redis.getRedis(user_id);
            //添加用户id与sessionId
            ArrayList<String> list = new ArrayList<>();
            list.add(user_id);
            list.add(sessionId);
            //批量删除
            redis.deleteRedisList(list);
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
        return ResultUtil.success(ResultEnum.SUCCESS, null);
    }

    /**
     * 忘记密码
     * @param changeAviationUser 用户信息
     * @param verificationCode 验证码
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> changePassword(Aviation_user changeAviationUser, String verificationCode) {
        try {
            //验证验证码
            String isCode = redis.getRedis(changeAviationUser.getUser_name());
            if (Validator.isNull(isCode) || !isCode.equals(verificationCode)) {
                return ResultUtil.success(ResultEnum.INVALID_VERIFICATION_CODE, null);
            }

            //删除验证码
            redis.deleteRedis(changeAviationUser.getUser_name());

            //验证用户状态
            Aviation_user aviationUser = loginMapper.Login(changeAviationUser.getUser_name());
            if (aviationUser == null) {
                return ResultUtil.success(ResultEnum.USER_NOT_EXIST, null);
            }

            //加密密码
            changeAviationUser.setUser_password(SecureUtil.md5(changeAviationUser.getUser_password() + aviationUser.getSalt()));

            //修改密码
            int changeId = loginMapper.changePassword(changeAviationUser);
            if (changeId <= 0) {
                return ResultUtil.success(ResultEnum.CHANGE_PASSWORD_HAS_FAILED, null);
            }

        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
        return ResultUtil.success(ResultEnum.SUCCESS, null);
    }

    /**
     * 使用id修改密码
     * @param oldPassword 旧密码
     * @param password 新密码
     * @param userId 用户id
     * @param session session
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> secondChangePassword(String oldPassword,String password, String userId,HttpSession session) {
        try {
            //验证用户状态
            Aviation_user aviationUser = loginMapper.LoginUserId(userId);
            if (aviationUser == null) {
                return ResultUtil.success(ResultEnum.USER_NOT_EXIST, null);
            }

            //验证密码是否正确
            String md5Pwd = SecureUtil.md5(oldPassword + aviationUser.getSalt());
            if (!md5Pwd.equals(aviationUser.getUser_password())) {
                return ResultUtil.success(ResultEnum.THE_PASSWORD_IS_INCORRECT, null);
            }

            //修改密码
            int changePassword = loginMapper.secondChangePassword(SecureUtil.md5(password + aviationUser.getSalt()), userId);
            if(changePassword>0){
                //清除登陆状态
                List<String> login=new ArrayList<>();
                login.add(aviationUser.getUser_name());
                login.add(session.getId());
                redis.deleteRedisList(login);
                return ResultUtil.success(ResultEnum.SUCCESS, null);
            }

            return ResultUtil.success(ResultEnum.CHANGE_PASSWORD_HAS_FAILED, null);
        }catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }

    private static String addressFiltering(String addres){
        String[] address = addres.split("\\|");
        String Filtering="";
        if(!address[2].equals("0")){
            Filtering+=address[2];
        }
        if(!address[3].equals("0") && !address[3].equals(address[2])){
            Filtering+=address[3];
        }
        return Filtering;
    }

}
